package com.cg.bank.util;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 数据库操作器
 *
 */
public class QueryRunner {
    // 连接池
    private DataSource dataSource;

    public QueryRunner() {
        // NOOP
    }

    /**
     * 创建指定数据库源(连接池)的QueryRunner
     * 此后的连接将由该数据源调度管理
     *
     * @param dataSource 数据源
     */
    public QueryRunner(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    /**
     * 增加，更新，删除操作(使用内部连接)
     *
     * @param sql    需更新的sql语句
     * @param params 需更新参数
     * @return 影响结果行
     */
    public int update(String sql, Object... params) throws SQLException {
        return update(dataSource.getConnection(), sql, params);
    }

    /**
     * 增加，更新，删除操作
     *
     * @param sql    需更新的sql语句
     * @param params sql参数列表
     * @return 影响结果行
     */
    public int update(Connection connection, String sql, Object... params) throws SQLException {
        PreparedStatement pstm = connection.prepareStatement(sql);// 获得预操作
        initParams(pstm, params);// 设置参数
        return pstm.executeUpdate();// 执行更新
    }

    /**
     * 查询操作
     *
     * @param sql             需要查询的sql
     * @param resultSetHandle 结果集处理器
     * @param params          参数列表
     * @return ObjectMapping 需要映射的对象
     */
    public <T> T query(Connection connection, String sql, ResultSetHander<T> resultSetHandle, Object... params) throws SQLException {
        PreparedStatement pstmt = connection.prepareStatement(sql);
        initParams(pstmt, params);
        // 执行查询并将结果集交由ResultSetHander处理
        return resultSetHandle.handle(pstmt.executeQuery());
    }

    /**
     * 查询操作(使用内部连接)
     *
     * @param sql             需要查询的sql
     * @param resultSetHandle 结果集处理器
     * @param params          参数列表
     * @return ObjectMapping 需要映射的对象
     */
    public <T> T query(String sql, ResultSetHander<T> resultSetHandle, Object... params) throws SQLException {
        return query(dataSource.getConnection(), sql, resultSetHandle, params);
    }

    /**
     * 单行查询
     *
     * @param connection 数据库连接
     * @param sql        需要查询的sql
     * @return affect row 结果数量
     * @throws SQLException
     */
    public <T> T query(Connection connection, String sql, ResultSetHander<T> resultSetHander) throws SQLException {
        // 获得连接预操作并执行查询
        ResultSet resultSet = connection.prepareStatement(sql).executeQuery();
        return resultSetHander.handle(resultSet);
    }
    
    /**
     * 为参数设置值
     *
     * @param pstm   预操作
     * @param params 参数数组
     * @throws SQLException
     */
    private void initParams(PreparedStatement pstm, Object[] params) throws SQLException {
        for (int i = 0; i < params.length; i++) {// 数据库从字段1开始
            pstm.setObject(i + 1, params[i]);
        }
    }
}